//! # 用户主体
//!
//! 表示已认证的用户或服务实体，包含身份信息、角色和权限。

use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::time::SystemTime;

/// 主体类型
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum PrincipalType {
    /// 普通用户
    User,
    /// 管理员用户
    Admin,
    /// 系统服务
    Service,
    /// 系统进程
    System,
    /// 匿名用户
    Anonymous,
    /// 自定义类型
    Custom(String),
}

/// 用户主体
/// 
/// 表示已认证的用户或服务实体
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Principal {
    /// 唯一标识符
    pub id: String,
    /// 显示名称
    pub name: String,
    /// 主体类型
    pub principal_type: PrincipalType,
    /// 角色集合
    pub roles: HashSet<String>,
    /// 权限集合
    pub permissions: HashSet<String>,
    /// 自定义属性
    pub attributes: HashMap<String, String>,
    /// 创建时间
    pub created_at: SystemTime,
    /// 过期时间（可选）
    pub expires_at: Option<SystemTime>,
    /// 最后活动时间
    pub last_activity: SystemTime,
}

impl Principal {
    /// 创建新的主体
    pub fn new(id: String, name: String, principal_type: PrincipalType) -> Self {
        let now = SystemTime::now();
        Self {
            id,
            name,
            principal_type,
            roles: HashSet::new(),
            permissions: HashSet::new(),
            attributes: HashMap::new(),
            created_at: now,
            expires_at: None,
            last_activity: now,
        }
    }

    /// 添加角色
    pub fn add_role(mut self, role: String) -> Self {
        self.roles.insert(role);
        self
    }

    /// 添加多个角色
    pub fn add_roles(mut self, roles: Vec<String>) -> Self {
        for role in roles {
            self.roles.insert(role);
        }
        self
    }

    /// 添加权限
    pub fn add_permission(mut self, permission: String) -> Self {
        self.permissions.insert(permission);
        self
    }

    /// 添加多个权限
    pub fn add_permissions(mut self, permissions: Vec<String>) -> Self {
        for permission in permissions {
            self.permissions.insert(permission);
        }
        self
    }

    /// 添加属性
    pub fn add_attribute(mut self, key: String, value: String) -> Self {
        self.attributes.insert(key, value);
        self
    }

    /// 添加多个属性
    pub fn add_attributes(mut self, attributes: HashMap<String, String>) -> Self {
        for (key, value) in attributes {
            self.attributes.insert(key, value);
        }
        self
    }

    /// 设置过期时间
    pub fn with_expiry(mut self, expires_at: SystemTime) -> Self {
        self.expires_at = Some(expires_at);
        self
    }

    /// 更新最后活动时间
    pub fn touch(mut self) -> Self {
        self.last_activity = SystemTime::now();
        self
    }

    /// 检查是否拥有特定角色
    pub fn has_role(&self, role: &str) -> bool {
        self.roles.contains(role)
    }

    /// 检查是否拥有任一角色
    pub fn has_any_role(&self, roles: &[&str]) -> bool {
        roles.iter().any(|role| self.has_role(role))
    }

    /// 检查是否拥有所有角色
    pub fn has_all_roles(&self, roles: &[&str]) -> bool {
        roles.iter().all(|role| self.has_role(role))
    }

    /// 检查是否拥有特定权限
    pub fn has_permission(&self, permission: &str) -> bool {
        self.permissions.contains(permission)
    }

    /// 检查是否拥有任一权限
    pub fn has_any_permission(&self, permissions: &[&str]) -> bool {
        permissions.iter().any(|perm| self.has_permission(perm))
    }

    /// 检查是否拥有所有权限
    pub fn has_all_permissions(&self, permissions: &[&str]) -> bool {
        permissions.iter().all(|perm| self.has_permission(perm))
    }

    /// 检查是否为管理员
    pub fn is_admin(&self) -> bool {
        matches!(self.principal_type, PrincipalType::Admin) || self.has_role("admin")
    }

    /// 检查是否为系统用户
    pub fn is_system(&self) -> bool {
        matches!(self.principal_type, PrincipalType::System | PrincipalType::Service)
    }

    /// 检查是否为匿名用户
    pub fn is_anonymous(&self) -> bool {
        matches!(self.principal_type, PrincipalType::Anonymous)
    }

    /// 检查是否已过期
    pub fn is_expired(&self) -> bool {
        self.expires_at
            .map(|expires| SystemTime::now() > expires)
            .unwrap_or(false)
    }

    /// 获取属性值
    pub fn get_attribute(&self, key: &str) -> Option<&str> {
        self.attributes.get(key).map(|s| s.as_str())
    }

    /// 获取所有角色
    pub fn get_roles(&self) -> Vec<&str> {
        self.roles.iter().map(|s| s.as_str()).collect()
    }

    /// 获取所有权限
    pub fn get_permissions(&self) -> Vec<&str> {
        self.permissions.iter().map(|s| s.as_str()).collect()
    }

    /// 创建匿名用户
    pub fn anonymous() -> Self {
        Self::new(
            "anonymous".to_string(),
            "Anonymous".to_string(),
            PrincipalType::Anonymous,
        )
    }

    /// 创建系统用户
    pub fn system(id: String, name: String) -> Self {
        Self::new(id, name, PrincipalType::System)
            .add_role("system".to_string())
    }

    /// 检查权限是否匹配通配符模式
    pub fn matches_permission_pattern(&self, pattern: &str) -> bool {
        if pattern.contains('*') {
            let regex_pattern = pattern.replace('*', ".*");
            self.permissions.iter().any(|perm| {
                regex::Regex::new(&regex_pattern)
                    .map(|re| re.is_match(perm))
                    .unwrap_or(false)
            })
        } else {
            self.has_permission(pattern)
        }
    }

    /// 获取权限级别（基于角色和权限的简单评分）
    pub fn get_permission_level(&self) -> u32 {
        let mut level = 0;
        
        // 基于角色的权限级别
        if self.has_role("admin") {
            level += 1000;
        }
        if self.has_role("moderator") {
            level += 500;
        }
        if self.has_role("user") {
            level += 100;
        }
        
        // 基于权限数量
        level += self.permissions.len() as u32;
        
        level
    }
}

impl PartialEq for Principal {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id && self.principal_type == other.principal_type
    }
}

impl Eq for Principal {}

impl std::hash::Hash for Principal {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state);
        self.principal_type.hash(state);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::Duration;

    #[test]
    fn test_principal_creation() {
        let principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        );
        
        assert_eq!(principal.id, "user123");
        assert_eq!(principal.name, "John Doe");
        assert_eq!(principal.principal_type, PrincipalType::User);
        assert!(principal.roles.is_empty());
        assert!(principal.permissions.is_empty());
        assert!(!principal.is_expired());
    }

    #[test]
    fn test_roles_and_permissions() {
        let principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        )
        .add_role("user".to_string())
        .add_role("editor".to_string())
        .add_permission("read:posts".to_string())
        .add_permission("write:posts".to_string());
        
        assert!(principal.has_role("user"));
        assert!(principal.has_role("editor"));
        assert!(!principal.has_role("admin"));
        
        assert!(principal.has_permission("read:posts"));
        assert!(principal.has_permission("write:posts"));
        assert!(!principal.has_permission("delete:posts"));
        
        assert!(principal.has_any_role(&["user", "admin"]));
        assert!(principal.has_all_roles(&["user", "editor"]));
        assert!(!principal.has_all_roles(&["user", "admin"]));
    }

    #[test]
    fn test_expiry() {
        let future_time = SystemTime::now() + Duration::from_secs(3600);
        let principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        ).with_expiry(future_time);
        
        assert!(!principal.is_expired());
        
        let past_time = SystemTime::now() - Duration::from_secs(3600);
        let expired_principal = Principal::new(
            "user456".to_string(),
            "Jane Doe".to_string(),
            PrincipalType::User,
        ).with_expiry(past_time);
        
        assert!(expired_principal.is_expired());
    }

    #[test]
    fn test_admin_and_system_checks() {
        let admin = Principal::new(
            "admin1".to_string(),
            "Admin User".to_string(),
            PrincipalType::Admin,
        );
        
        assert!(admin.is_admin());
        assert!(!admin.is_system());
        assert!(!admin.is_anonymous());
        
        let system = Principal::system(
            "service1".to_string(),
            "System Service".to_string(),
        );
        
        assert!(!system.is_admin());
        assert!(system.is_system());
        assert!(system.has_role("system"));
        
        let anonymous = Principal::anonymous();
        assert!(anonymous.is_anonymous());
        assert_eq!(anonymous.id, "anonymous");
    }

    #[test]
    fn test_permission_level() {
        let admin = Principal::new(
            "admin1".to_string(),
            "Admin".to_string(),
            PrincipalType::Admin,
        ).add_role("admin".to_string());
        
        let user = Principal::new(
            "user1".to_string(),
            "User".to_string(),
            PrincipalType::User,
        ).add_role("user".to_string());
        
        assert!(admin.get_permission_level() > user.get_permission_level());
    }

    #[test]
    fn test_attributes() {
        let principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        )
        .add_attribute("department".to_string(), "Engineering".to_string())
        .add_attribute("location".to_string(), "San Francisco".to_string());
        
        assert_eq!(principal.get_attribute("department"), Some("Engineering"));
        assert_eq!(principal.get_attribute("location"), Some("San Francisco"));
        assert_eq!(principal.get_attribute("nonexistent"), None);
    }
}